package com.vimi8.ebb.auth;

import com.vimi8.ebb.auth.configuration.*;
import com.vimi8.ebb.auth.service.DBUserDetailsService;
import com.vimi8.ebb.auth.service.UserAuthorityService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.*;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.security.KeyPair;

@SpringBootApplication
@EnableSwagger2
public class Swagger2SpringBoot {
    private static final Logger logger =  LoggerFactory.getLogger("Swagger2SpringBoot");

	public static void main(String[] args) throws Exception {
			SpringApplication.run(Swagger2SpringBoot.class, args);
	}

    @Configuration
    protected static class AuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter {

        @Autowired
        DBUserDetailsService dbUserDetailsService;

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(new AuthenticationProviderImpl(dbUserDetailsService))
            .userDetailsService(new UserDetailsServiceImpl(dbUserDetailsService));
        }
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2AuthorizationConfig extends
            AuthorizationServerConfigurerAdapter {

        @Value("${security.oauth2.resource.id}")
        private String resourceId;

        @Autowired
        private AuthenticationManager authenticationManager;

        @Autowired
        private UserAuthorityService userAuthorityService;

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.withClientDetails(new ClientDetailsServiceImpl());
        }

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.pathMapping("/oauth/token", "/token")
                    .pathMapping("/oauth/authorize","/authorize")
                    .pathMapping("/oauth/authorize","/authorize")
                    .pathMapping("/oauth/confirm_access","/confirm_access");
            KeyPair keyPair = new KeyStoreKeyFactory(
                    new ClassPathResource("server.jks"), "letmein".toCharArray())
                    .getKeyPair("mytestkey", "changeme".toCharArray());
            endpoints.authenticationManager(authenticationManager).accessTokenConverter(new JwtAccessTokenConverterImpl(resourceId,userAuthorityService,keyPair));
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
        }
    }

    @EnableResourceServer
    protected static class ResourceServerConfigurer extends ResourceServerConfigurerAdapter{
        @Value("${security.oauth2.resource.id}")
        private String resourceId;

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          //  resources.resourceId(resourceId);
                        resources.resourceId(resourceId).tokenExtractor(new CookieTokenExtractor());
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            //使用注解式替代@PreAuthorize("#oauth2.hasScope('***')"),注意注解所在的接口或类必须有@RestController注解,否则会导致未知错误
            //http.authorizeRequests().antMatchers(HttpMethod.GET, "/file/**").access("#oauth2.hasScope('read:oss-server')");
            //http.authorizeRequests().antMatchers(HttpMethod.POST, "/file/").access("#oauth2.hasScope('write:oss-server')");

            http.authorizeRequests()
                    .antMatchers(HttpMethod.GET, "/login.html").permitAll()
                    .antMatchers(HttpMethod.GET, "/login/verifyCode.jpg").permitAll()
                    .antMatchers(HttpMethod.GET, "/404.html").permitAll()
                    .antMatchers(HttpMethod.POST, "/login/").permitAll()//登录接口
                    .antMatchers(HttpMethod.POST, "/refresh/").permitAll()//刷新token接口
                    .antMatchers(HttpMethod.POST, "/user/").permitAll()//新加用户
                    .antMatchers(HttpMethod.PUT, "/user/").permitAll()//修改资料
                    .antMatchers(HttpMethod.PUT, "/user/password/").permitAll()//修改密码
                    .antMatchers(HttpMethod.POST, "/user/codes/").permitAll()//发送手机验证码
                    .antMatchers(HttpMethod.POST, "/org/").permitAll()//注册组织
                    .antMatchers(HttpMethod.GET, "/org/emp/").permitAll()//查询组织汇总信息
                    .antMatchers(HttpMethod.POST, "/signature/").permitAll()//;//oss调用签名
                    .antMatchers(HttpMethod.GET, "/farmInfoList/").permitAll()//;//查询农场测试
                     .antMatchers(HttpMethod.POST,"/user/test/transaction/").permitAll()//事物测试
                    .antMatchers(HttpMethod.GET,"/socket/**").permitAll()
                    .antMatchers(HttpMethod.POST,"/socket/**").permitAll()
                    .antMatchers(HttpMethod.GET,"/topic/**").permitAll()
                    .antMatchers(HttpMethod.POST,"/topic/**").permitAll()
                    .antMatchers(HttpMethod.GET,"/app/**").permitAll()
                    .antMatchers(HttpMethod.POST,"/app/**").permitAll()
                     .antMatchers(HttpMethod.GET,"/user/qrcode/**").permitAll()
                    .antMatchers(HttpMethod.POST, "/org/corp/batch/").permitAll()
                    .antMatchers(HttpMethod.POST, "/org/corp/import/").permitAll();
            //anyRequest() authenticated()必须在最后
            ((ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
        }

        @Configuration
        @EnableGlobalMethodSecurity(prePostEnabled = true)
        public static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
            @Override
            protected MethodSecurityExpressionHandler createExpressionHandler() {
                return new OAuth2MethodSecurityExpressionHandler();
            }
        }
    }
}